/*
 *  Helpers.m
 *  pogostick
 *
 *  Created by daddy (chuck@kollar.com) on 8/26/09.
 *  Copyright 2009 Charles P. Kollar All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#import "Helpers.h"
#import "Menu.h"


#define WORLD_HEIGHT                        3000.0f
#define FLOOR_SEGMENT_RADIUS                40.0f

/* This is the y component of the terrain height data. The x component
 is assumed beginning at 0.0 and continuing at intervals of xDelta */
#define X_DELTA_TERRAIN                     200
#define FIRST_X_POINT                       -2000.0f

// set in menu.m
extern int soundp, musicp;

extern cpFloat footRadius;
extern cpFloat spaceGravity;

#if 0
void makeStaticBox(float x, float y, float width, float height, cpSpace *space, cpBody *staticBody){
	cpShape *shape;
	
	shape = cpSegmentShapeNew(staticBody, cpv(x,y), cpv(x+width, y), 1.0f);
	shape->e = 1.0f; shape->u = 1.0f;
	shape->collision_type = kColl_Ground;
	cpSpaceAddStaticShape(space, shape);
	
	shape = cpSegmentShapeNew(staticBody, cpv(x+width, y), cpv(x+width, y-height ), 1.0f);
	shape->e = 1.0f; shape->u = 1.0f;
	shape->collision_type = kColl_Ground;
	cpSpaceAddStaticShape(space, shape);
	
	shape = cpSegmentShapeNew(staticBody, cpv(x+width, y-height), cpv(x, y-height ), 1.0f);
	shape->e = 1.0f; shape->u = 1.0f;
	shape->collision_type = kColl_Ground;
	cpSpaceAddStaticShape(space, shape);
	
	shape = cpSegmentShapeNew(staticBody, cpv(x, y-height ), cpv(x, y), 1.0f);
	shape->e = 1.0f; shape->u = 1.0f;
	shape->collision_type = kColl_Ground;
	cpSpaceAddStaticShape(space, shape);
}

cpFloat terrain_data_y[] = {
100.0, 80.0, 60.0, 40.0, 50.0, 20.0, 15.0, 10.0, 5.0, 5.0, 5.0,
10.0, 20.0, 80.0, 50.0, 100.0, 130.0, 160.0, 200.0, 190.0, 190.0,
230.0, 250.0, 270.0, 310.0, 330.0, 340.0, 320.0, 330.0, 350.0,
380.0, 390.0, 400.0, 380.0, 370.0, 390.0, 430.0, 450.0, 476.0,
500.0, 510.0, 520.0, 480.0, 500.0, 520.0, 530.0, 540.0, 550.0,
560.0, 520.0, 530.0, 540.0, 550.0, 560.0, 560.0, 580.0, 600.0,
600.0, 600.0, 610.0, 620.0, 630.0, 600.0, 640.0, 650.0, 650.0,
660.00, 660.00, 660.00, 660.00, 673.21, 688.42, 694.56, 692.55,
685.40, 676.12, 667.75, 662.45, 658.93, 655.42, 650.17, 641.49,
627.92, 610.08, 589.01, 565.71, 541.23, 516.58, 492.56, 469.57,
447.97, 428.13, 410.60, 397.25, 392.66, 394.89, 400.70, 406.82,
410.93, 413.87, 416.91, 421.30, 428.24, 436.05, 440.41, 437.09,
421.93, 394.41, 355.57, 308.78, 257.99, 207.18, 160.31, 120.81,
89.20, 65.17, 48.43, 38.67, 36.68, 45.03, 64.17, 92.26, 128.76,
173.27, 224.20, 278.84, 334.48, 388.43, 438.31, 483.95, 525.96,
564.95, 601.54, 633.88, 655.05, 665.87, 667.79, 662.25, 650.01,
629.92, 604.68, 577.50, 551.55, 529.69, 512.49, 502.04, 500.20,
502.72, 508.57, 518.31, 531.15, 545.99, 561.70, 577.30, 593.74,
610.97, 628.13, 644.35, 658.81, 672.13, 684.78, 696.72, 708.00,
718.65, 728.17, 736.14, 742.62, 747.63, 751.20, 752.58, 750.20,
743.02, 730.05, 709.98, 682.99, 651.49, 616.61, 579.47, 541.18,
503.87, 471.12, 444.10, 423.86, 411.44, 407.95, 414.29, 430.28,
453.64, 482.36, 514.10, 545.66, 577.48, 610.42, 645.32, 682.66,
719.61, 754.76, 787.26, 816.26, 840.95, 861.10, 876.94, 888.71,
896.61, 900.84, 900.46, 894.59, 882.69, 864.24, 838.69, 805.77,
765.56, 718.19, 670.07, 626.07, 586.87, 551.65, 518.20, 484.33,
447.81, 408.39, 367.51, 324.70, 279.44, 231.25, 181.20, 134.59,
96.96, 66.40, 40.75, 18.74, 1.97, -8.96, -13.56, -11.33, -2.28,
11.64, 29.88, 52.04, 78.07, 108.53, 139.94, 171.90, 204.54,
238.00, 272.25, 305.61, 336.90, 365.19, 389.61, 409.28, 424.38,
434.79, 438.85, 437.12, 431.08, 422.77, 412.26, 398.92, 382.10,
361.16, 336.82, 311.06, 285.61, 262.18, 242.50
};
#define TERRAIN_POINTS	(sizeof(terrain_data_y) / sizeof(cpFloat))

cpFloat findLowestTerrainY (cpVect pos, cpFloat screenWidth) {
	int start = (pos.x-screenWidth/2)/X_DELTA_TERRAIN;
	int end = (pos.x+screenWidth/2)/X_DELTA_TERRAIN;
	if (start < 0) start = 0;
	if (start > TERRAIN_POINTS) start = TERRAIN_POINTS -4;
	if (end > TERRAIN_POINTS) end = TERRAIN_POINTS;
	cpFloat minY = terrain_data_y[start];
	for (int i=start; i<end; i++) { if (terrain_data_y[i] < minY) minY = terrain_data_y[i]; }
	return minY;
}

void buildTerrainFlootInSpace(cpSpace *space, cpBody *staticBody) {
	/* This loop adds line segments for the terrain. */
	int i;
	cpVect a = cpv(FIRST_X_POINT, terrain_data_y[0]);
	for(i=1; i<TERRAIN_POINTS; i++){
		cpVect b = cpv((cpFloat)i*X_DELTA_TERRAIN, terrain_data_y[i]);
		
		/* Collision shapes are attached to rigid bodies. When the rigid
		 body moves, the collision shapes attached to it move as
		 well. For the ground, we want to attach its collision shapes
		 (the line segments) to our static, non-moving body that we've
		 created. */
        // Through experimentation it was found that the radius of 30 kept
        // the ball on the pogostick from going through the ground and getting
        // stuck. The larger that you make this value, the farther from the
        // segment surface the pogostick ball will go. So it's a trade-off
        // between keeping the ball from going through the floor and it looking
        // like the ball strikes above the ground. The other alternative is to
        // make the ball larger, but this tends to look silly.
		cpShape *seg = cpSegmentShapeNew(staticBody, a, b, FLOOR_SEGMENT_RADIUS);
		
		/* After you create a shape, you'll probably want to set some of
		 it's properties. Possibilities include elasticity (e), surface
		 velocity (surface_v), and friction (u). We'll just set the
		 friction. */
		seg->u = 1.0f;
		seg->collision_type = kColl_Ground;
		
		/* Lastly, we need to add it to a space for it to do any
		 good. Because the ground never moves, we want to add it to the
		 static shapes to allow Chipmunk to cache the collision
		 information. Adding the line segments to the active shapes
		 would work, but would be slower.  */
		cpSpaceAddStaticShape(space, seg);
		
		a = b;
	}
}

void boxAroundTerrainInSpace(cpSpace *space, cpBody *staticBody) {
    cpVect a = cpv(FIRST_X_POINT, terrain_data_y[0]);
    cpVect b = cpv(FIRST_X_POINT, terrain_data_y[0]+WORLD_HEIGHT);
    cpShape *seg = cpSegmentShapeNew(staticBody, a, b, FLOOR_SEGMENT_RADIUS);
    seg->u = 1.0f;
    seg->collision_type = kColl_Ground;
    cpSpaceAddStaticShape(space, seg);
    a = cpv(FIRST_X_POINT+TERRAIN_POINTS*X_DELTA_TERRAIN,terrain_data_y[0]+WORLD_HEIGHT);  
    seg = cpSegmentShapeNew(staticBody, b, a, FLOOR_SEGMENT_RADIUS);
    seg->u = 1.0f;
    seg->collision_type = kColl_Ground;
    cpSpaceAddStaticShape(space, seg);
    b = cpv(FIRST_X_POINT+TERRAIN_POINTS*X_DELTA_TERRAIN,terrain_data_y[TERRAIN_POINTS-1]);
    seg = cpSegmentShapeNew(staticBody, a, b, FLOOR_SEGMENT_RADIUS);
    seg->u = 1.0f;
    seg->collision_type = kColl_Ground;
    cpSpaceAddStaticShape(space, seg);
}

void build_terrain_in_space(cpSpace *space, cpBody *staticBody) {
    buildTerrainFlootInSpace(space, staticBody);
    boxAroundTerrainInSpace(space, staticBody);
}

void build_terrain_in_new(cpSpace *space, cpBody *staticBody) {
	cpShape *shape;
	cpVect verts[4];
	/* This loop adds line segments for the terrain. */
	int i;
	//cpVect a = cpv(FIRST_X_POINT, terrain_data_y[0]);
	for(i=0; i<TERRAIN_POINTS-1; i++){
		//cpVect b = cpv(i*X_DELTA_TERRAIN, terrain_data_y[i]);
		
		/* Collision shapes are attached to rigid bodies. When the rigid
		 body moves, the collision shapes attached to it move as
		 well. For the ground, we want to attach its collision shapes
		 (the line segments) to our static, non-moving body that we've
		 created. */
		//makeStaticBox(i*X_DELTA_TERRAIN, terrain_data_y[i], X_DELTA_TERRAIN, 40.0f, staticBody);
		cpFloat maxY=terrain_data_y[i+1], minY=terrain_data_y[i];
        if (minY > maxY) {
            maxY=terrain_data_y[i]; minY=terrain_data_y[i+1];
        }
        if (minY + 5.0f > maxY) minY -= 5.0f;
        
		verts[0] = cpv((cpFloat)i*X_DELTA_TERRAIN, minY);
		verts[1] = cpv((cpFloat)i*X_DELTA_TERRAIN, maxY);
		verts[2] = cpv((cpFloat)(i+1)*X_DELTA_TERRAIN, maxY);
		verts[3] = cpv((cpFloat)(i+1)*X_DELTA_TERRAIN, minY);

        //NSLog(@"i*X_DELTA_TERRAIN %d  minY %f  maxY %f\n", i*X_DELTA_TERRAIN, minY, maxY);

		shape = cpPolyShapeNew(staticBody, (sizeof(verts)/sizeof(cpVect)), verts, cpvzero);
		shape->e = 0.0f; shape->u = 1.0f;
		shape->collision_type = kColl_Ground;
		cpSpaceAddStaticShape(space, shape);
		
		//cpShape *seg = cpSegmentShapeNew(staticBody, a, b, 1.0f);
		
		/* After you create a shape, you'll probably want to set some of
		 it's properties. Possibilities include elasticity (e), surface
		 velocity (surface_v), and friction (u). We'll just set the
		 friction. */
		//seg->u = 1.0;
		//seg->collision_type = kColl_Ground;
		
		/* Lastly, we need to add it to a space for it to do any
		 good. Because the ground never moves, we want to add it to the
		 static shapes to allow Chipmunk to cache the collision
		 information. Adding the line segments to the active shapes
		 would work, but would be slower.  */
		//cpSpaceAddStaticShape(space, seg);
		
		//a = b;
	}
}

#endif

